/*
 * @Author: xiaosihan
 * @Date: 2021-04-10 02:44:01
 * @Last Modified by: 肖思汗
 * @Last Modified time: 2025-05-30 17:54:36
 */
import threeUtils from "./threeUtils";

function bezier(arr, t) {
    const ut = 1 - t;
    const a1 = arr[1] * ut + arr[2] * t;
    const result = ((arr[0] * ut + arr[1] * t) * ut + a1 * t) * ut + (a1 * ut + (arr[2] * ut + arr[3] * t) * t) * t;
    return result;
}
// 过渡动画插件
export default class Transition {
    /**
     *Creates an instance of transition.
     * @param {{ [key: string]: number }} // 初始值
     * @param {[0.8, 0, 0.2, 1]} // 贝塞尔曲线
     * @param {number} [duration=1000]  // 过渡时间
     * @memberof transition
     */
    constructor(param, bezier = [0.8, 0, 0.2, 1], duration = 500) {
        this.setDuration(duration);
        this.setBezier(bezier);
        this.reset(param);
    }
    // 所有的 key 的枚举
    _keys: Array<string> = [];
    // 贝塞尔曲线
    _bezier = [0.8, 0, 0.2, 1];
    // x轴贝塞尔
    _Xbezier = [0, 0.8, 0.2, 1];
    // y轴贝塞尔
    _Ybezier = [0, 0, 1, 1];
    setBezier(bezier = [0.8, 0, 0.2, 1]) {
        this._bezier = [...bezier];
        this._Xbezier = [0, bezier[0], bezier[2], 1];
        this._Ybezier = [0, bezier[1], bezier[3], 1];
        return this;
    }
    // 当前时间戳
    timeTemp = Date.now();
    // 过渡时间
    _duration = 0;
    //延时
    _delay = 0;
    // 设置过渡时间
    setDuration(duration = 500) {
        setTimeout(() => {
            this._duration = duration;
        }, 0);
        return this;
    }
    // 设置延时
    setDelay(delay = 0) {
        this._delay = delay;
        return this;
    }
    // 存储 每个参数的 起始位置 起始时间 终止位置  终止时间
    _ = {};
    // 数据改变的事件回调
    onChangeCall = (josn) => { };
    //结束的事件回调
    onDoneCall = (josn) => { };
    // 执行过度动画
    run({ timeTemp }) {
        this.timeTemp = timeTemp;
        this.onChangeCall(this.getJson());
        if (this.isDone()) {
            this.onDoneCall(this.getJson());
            threeUtils.removeEventListener("requestAnimationFrame", this.runbindThis);
        }
        return this;
    }
    runbindThis = this.run.bind(this);
    // 设置动画对象的回调事件
    onChange(onChangeCall) {
        this.onChangeCall = onChangeCall;
        this.onChangeCall(this.getJson());
        return this;
    }
    //设置动画对象的
    onDone(onDoneCall) {
        this.onDoneCall = onDoneCall;
        return this;
    }
    // 计算当前 key 的值
    get(key) {
        key = String(key);
        if (this._keys.includes(key) && this.timeTemp < (this._[key + "_startTime"] + this._duration)) {
            let start = this._[key + "_start"];
            let end = this._[key + "_end"];
            let timeProgress = Math.min(1, Math.max(0, (this.timeTemp - this._[key + "_startTime"]) / this._duration));
            // 斜率
            let t = 0;
            // 微分法 求斜率t
            while (bezier(this._Xbezier, t + 0.1) < timeProgress) {
                t += 0.1;
            }
            while (bezier(this._Xbezier, t + 0.01) < timeProgress) {
                t += 0.01;
            }
            while (bezier(this._Xbezier, t + 0.001) < timeProgress) {
                t += 0.001;
            }
            t = Math.min(1, Math.max(0, t)); // 斜率最大为1
            // 通过斜率求y值
            return (bezier(this._Ybezier, t) * (end - start)) + start;
        }
        else if (this._keys.includes(key) && this.timeTemp >= (this._[key + "_startTime"] + this._duration)) {
            return this._[key + "_end"];
        }
        // `没有 ${ key } 的值`;
        return 0;
    }
    async set(param) {
        let timetemp = Date.now() + this._delay;
        ;
        for (let key in param) {
            // 有就赋值
            if (this._keys.includes(key) && Math.abs(param[key] - this._[key + "_end"]) > 0.0001) {
                this._[key + "_start"] = this.get(key);
                this._[key + "_end"] = param[key];
                // 起始时间
                this._[key + "_startTime"] = timetemp;
                // 执行状态未完成
                this._isDone = false;
                // 没有就添加一个
            }
            else if (!this._keys.includes(key)) {
                this._[key + "_start"] = param[key];
                this._[key + "_end"] = param[key];
                // 起始时间
                this._[key + "_startTime"] = timetemp - this._duration;
                // 执行状态未完成
                this._isDone = false;
            }
            if (!this._keys.includes(key)) {
                this._keys.push(key);
            }
            // // 执行状态未完成
            // this._isDone = false;
        }
        if (!this._isDone) {
            threeUtils.removeEventListener("requestAnimationFrame", this.runbindThis);
            threeUtils.addEventListener("requestAnimationFrame", this.runbindThis);
            await new Promise(resolve => setTimeout(resolve, 50));
            await new Promise(resolve => setTimeout(resolve, this._duration));
        }
        return this;
    }
    // 重置起始和终止位置
    reset(param) {
        for (let key in param) {
            if (!this._keys.includes(key)) {
                this._keys.push(key);
            }
            this._[key + "_start"] = param[key];
            this._[key + "_end"] = param[key];
            this._[key + "_startTime"] = -this._duration;
        }
        if (this.onChangeCall) {
            this.onChangeCall(this.getJson());
            this.onDoneCall(this.getJson());
        }
        this._isDone = true;
        return this;
    }
    // 获取过渡对象上面的key
    getKeys() {
        return [...this._keys];
    }
    // 判断是否有这个参数
    hasKey(key) {
        return this._keys.includes(key);
    }
    // 获取全部参数
    getJson() {
        let keys = this.getKeys();
        let json = {};
        keys.map(key => {
            json[key] = this.get(key);
        });
        return json;
    }
    _isDone = false;
    // 是否执行完成了
    isDone() {
        if (this._isDone) {
            return true;
        }
        let isisDone = false;
        for (let i in this._keys) {
            isisDone = this._[this._keys[i] + "_startTime"] + this._duration < this.timeTemp;
            // 只要有一个没有完成 都算没有完成 过渡
            if (!isisDone) {
                return false;
            }
        }
        if (!this._isDone) {
            this._isDone = true;
            return false;
        }
        return true;
    }
}
